package cn.com.digitalnet.ad.base;

import static org.assertj.core.api.Assertions.*;

import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.transaction.annotation.Transactional;

import cn.com.digitalnet.ad.repository.mybatis.CrudMao;
import cn.com.digitalnet.ad.util.EhcacheUtil;
import cn.com.digitalnet.ad.util.Holder;

import com.google.common.collect.Maps;

@Transactional
public abstract class CrudService<E extends IdEntity> {
	
	@Autowired protected EhcacheUtil ehcacheUtil;
	
	protected abstract CrudMao<E> mao();

	protected Map<String, Object> param(String key, Object value){
		Map<String, Object> param = Maps.newHashMap();
		param.put(key, value);
		return param;
	}
	
	private List<E> doQuery(Map<String, Object> params){
		//附带当前登录用户id查询
		if(Holder.user.get() != null && Holder.user.get().getId() != 1){
			params.put("userId", Holder.user.get().getId());
		}
		return mao().query(params);
	}
	
	private int doCount(Map<String, Object> params){
		//附带当前登录用户id查询
		if(Holder.user.get() != null && Holder.user.get().getId() != 1){
			params.put("userId", Holder.user.get().getId());
		}
		return mao().count(params);
	}
	
	public void save(E e) {
		if(e.getAddTime() == null){
			e.setAddTime(new Date());
		}
		if(e.getAddUser() == null){
			e.setAddUser(Holder.user.get());
		}
		mao().save(e);
		doAfterSave(e);
	}
	
	protected void doAfterSave(E e){
		//保存之后做些事情的扩展点
		//典型的是使用刚新建的实体的id（保存之后才会知道）做些事情
		assertThat(e.getId()).isNotNull();
	}
	
	public void update(E e) {
		E oldOne = this.findOne(e.getId());
		doBeforeUpdate();
		e.setUpdateTime(new Date());
		e.setUpdateUser(Holder.user.get());
		mao().update(e);
	}
	
	
	//更新之前做的事情
	protected void doBeforeUpdate() {
		//...
	}

	public void delete(Long id) {
		mao().delete(id);
	}
	
	public void submit(Long id){
		mao().submit(id);
	}
	
	/**
	 * 根据id获得唯一结果（包含草稿状态实体，慎用）
	 * @author qidafang
	 */
	public E findOne(Long id) {
		Map<String, Object> params = Maps.newHashMap();
		params.put("id", id);
		return findOne(params);
	}

	/**
	 * 根据查询条件获得唯一结果（包含草稿状态实体，慎用）
	 * @author qidafang
	 */
	public E findOne(Map<String, Object> params){
		List<E> l = this.doQuery(params);
		if(l.size() == 0){
			return null;
		}else if(l.size() > 1){
			Holder.errors.get().addError("查询结果不唯一");
			throw new RuntimeException("查询结果不唯一");
		}else{
			return l.get(0);
		}
	}
	
	/**
	 * 根据查询条件获得唯一结果，并且必须是有效数据
	 * @author qidafang
	 */
	public E findEnabledOne(Map<String, Object> params){
		params.put("isenabled", 1L);
		return this.findOne(params);
	}
	
	/**
	 * 获得所有实体（包含草稿状态实体，慎用）
	 * @author qidafang
	 */
	public List<E> findAll(){
		Map<String, Object> params = Maps.newHashMap();
		return this.findAll(params);
	}
	
	/**
	 * 获得满足条件的所有实体（包含草稿状态实体，慎用）
	 * @author qidafang
	 */
	public List<E> findAll(Map<String, Object> params){
		return this.doQuery(params);
	}
	
	/**
	 * 获得所有已发布的实体
	 * @author qidafang
	 */
	public List<E> findEnabledAll(){
		Map<String, Object> params = Maps.newHashMap();
		return this.findEnabledAll(params);
	}
	
	/**
	 * 获得满足条件的所有已发布的实体
	 * @author qidafang
	 */
	public List<E> findEnabledAll(Map<String, Object> params){
		params.put("isenabled", 1L);
		return this.doQuery(params);
	}
	
	/**
	 * 根据查询条件、分页条件，获得分页结果
	 * @author qidafang
	 */
	public Page<E> page(Map<String, Object> searchParams,PageRequest pageRequest) {
		Map<String, Object> params = Maps.newHashMap();
		for(Map.Entry<String, Object> entry : searchParams.entrySet()){
			if(entry.getValue() != null && !entry.getValue().equals("")){
				params.put(entry.getKey(), entry.getValue());
			}
		}
		if(pageRequest != null){
			params.put("order", pageRequest.getSort().iterator().next().getProperty());
			params.put("orderDire", pageRequest.getSort().iterator().next().getDirection() == Direction.ASC ? "asc" : "desc");
			params.put("start", (pageRequest.getPageNumber()) * pageRequest.getPageSize());
			params.put("limit", pageRequest.getPageSize());
		}
		List<E> list = this.doQuery(params);
		int count = this.doCount(params);
		PageImpl<E> page = new PageImpl(list, pageRequest, count);
		return page;
	}

	/**
	 * 导入excel
	 * @author qidafang
	 */
	public void importExcel(Workbook workbook){
		Sheet sheet = workbook.getSheetAt(0);
		int rowCount = sheet.getPhysicalNumberOfRows();
		for(int i = getFirstDataRowIndexOfExcel(); i < rowCount; i++){
			E e = this.initByExcelRow(sheet, i);
			if(e != null){
				this.save(e);
				doAfterSaveEntityWhenImport(e);
			}
		}
	}
	
	/**
	 * 导入excel模板中第几行开始不是表头而是真实数据
	 * @author qidafang
	 */
	protected int getFirstDataRowIndexOfExcel(){
		return 1;
	}
	
	/**
	 * 从excel产生了一个实体并保存后做些什么的扩展点
	 * @author qidafang
	 */
	protected void doAfterSaveEntityWhenImport(E e){
		//
	}
	
	/**
	 * 具体service应该实现：从某个sheet的某一行产生一个实体
	 * @author qidafang
	 */
	public E initByExcelRow(Sheet sheet, int rowIndex){
		return null;
	}
}
